use std::{env, vec};

use cross_rs::{IResult, string::extend::StringExentd};

use log::LevelFilter;
use once_cell::sync::Lazy;

pub static EXE_FILE_NAME: Lazy<String> = Lazy::new(|| {
    let mut filename = std::env::current_exe()
        .unwrap_or_default()
        .as_path()
        .file_name()
        .map(|x| x.to_str().map(|x| x.to_string()))
        .unwrap_or_default()
        .unwrap_or_default();
    if filename.find(|x| x == '.').is_some() {
        let (filename2, _) = filename.split_two(".");
        filename = filename2;
    }
    filename
});

pub fn init() -> IResult {
    use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
    use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
    use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
    use log4rs::{
        append::{
            console::{ConsoleAppender, Target},
            rolling_file::RollingFileAppender,
        },
        config::{Appender, Root},
        encode::pattern::PatternEncoder,
        filter::threshold::ThresholdFilter,
    };

    let dir = format!("logs-{}", EXE_FILE_NAME.to_string());
    println!("logs path: {}", dir);
    // let parttern = "{d(%Y-%m-%d %H:%M:%S.%f)} {l} [{t}:{L}] {m}\n";
    let parttern = "{d(%Y-%m-%d %H:%M:%S.%f)} {l} [{f}:{L}] {m}\n";
    let file_size = 1024 * 1024 * 100;
    // let file_size = 512;

    let logfile_get = |filter: log::LevelFilter, level_name: &str| {
        let builder = RollingFileAppender::builder()
            .encoder(Box::new(PatternEncoder::new(parttern)))
            .build(
                format!("{dir}/{level_name}.log"),
                Box::new(CompoundPolicy::new(
                    Box::new(SizeTrigger::new(file_size)),
                    Box::new(FixedWindowRoller::builder().base(1).build(format!("{dir}/{level_name}.{{}}.log").as_str(), 30).unwrap()),
                )),
            )
            .unwrap();
        Appender::builder().filter(Box::new(ThresholdFilter::new(filter))).build(level_name, Box::new(builder))
    };

    let mut appenders = vec!["debug", "info", "warn", "error"];

    // 开发环境打印日志到控制台,release编译,生产环境时不打印
    if dev_or_prod!(true, false) {
        appenders.push("console");
    }

    let config = log4rs::Config::builder()
        .appender(logfile_get(log::LevelFilter::Debug, "debug"))
        .appender(logfile_get(log::LevelFilter::Info, "info"))
        .appender(logfile_get(log::LevelFilter::Warn, "warn"))
        .appender(logfile_get(log::LevelFilter::Error, "error"))
        .appender(Appender::builder().filter(Box::new(ThresholdFilter::new(log::LevelFilter::Debug))).build(
            "console",
            Box::new(ConsoleAppender::builder().encoder(Box::new(PatternEncoder::new(parttern))).target(Target::Stdout).build()),
        ))
        .logger(log4rs::config::Logger::builder().build("ureq", LevelFilter::Info))
        .logger(log4rs::config::Logger::builder().build("rbatis", dev_or_prod!(LevelFilter::Info, LevelFilter::Warn)))
        .logger(log4rs::config::Logger::builder().build("rustls", LevelFilter::Info))
        .logger(log4rs::config::Logger::builder().build("reqwest", LevelFilter::Info))
        .logger(log4rs::config::Logger::builder().build("hyper", LevelFilter::Info))
        .logger(log4rs::config::Logger::builder().build("sled", LevelFilter::Info))
        .logger(log4rs::config::Logger::builder().build("isahc", LevelFilter::Warn))
        .logger(log4rs::config::Logger::builder().build("mqtt_async_client", LevelFilter::Warn))
        .logger(log4rs::config::Logger::builder().build("teloxide", LevelFilter::Off))
        .logger(log4rs::config::Logger::builder().build("tao::platform_impl", LevelFilter::Error))
        .build(Root::builder().appenders(appenders).build(log::LevelFilter::Debug))
        .unwrap();

    log4rs::init_config(config)?;
    Ok(())
}

pub fn init_by_off(off_libs: impl Into<String>) -> IResult {
    let name = EXE_FILE_NAME.to_string();
    init_by_off2(off_libs, name)
}

pub fn init_by_off2(off_libs: impl Into<String>, log_name: impl Into<String>) -> IResult {
    let off_libs = off_libs.into();
    use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
    use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
    use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
    use log4rs::{
        append::{
            console::{ConsoleAppender, Target},
            rolling_file::RollingFileAppender,
        },
        config::{Appender, Root},
        encode::pattern::PatternEncoder,
        filter::threshold::ThresholdFilter,
    };

    let dir = format!("logs-{}", log_name.into());
    println!("logs path: {}", dir);
    // let parttern = "{d(%Y-%m-%d %H:%M:%S.%f)} {l} [{t}:{L}] {m}\n";
    let parttern = "{d(%Y-%m-%d %H:%M:%S.%f)} {l} [{f}:{L}] {m}\n";
    let file_size = 1024 * 1024 * 100;
    // let file_size = 512;

    let logfile_get = |filter: log::LevelFilter, level_name: &str| {
        let builder = RollingFileAppender::builder()
            .encoder(Box::new(PatternEncoder::new(parttern)))
            .build(
                format!("{dir}/{level_name}.log"),
                Box::new(CompoundPolicy::new(
                    Box::new(SizeTrigger::new(file_size)),
                    Box::new(FixedWindowRoller::builder().base(1).build(format!("{dir}/{level_name}.{{}}.log").as_str(), 30).unwrap()),
                )),
            )
            .unwrap();
        Appender::builder().filter(Box::new(ThresholdFilter::new(filter))).build(level_name, Box::new(builder))
    };

    let appenders = vec!["debug", "info", "warn", "error", "console"];

    // 开发环境打印日志到控制台,release编译,生产环境时只有warn,error日志才打印
    let log_level = env::var("RUST_LOG").unwrap_or_else(|_| "warn".to_string());

    // 考虑 RUST_LOG = "debug,xxx=warn" 的情况
    let log_level = log_level.split(",").map(|x| x.trim().to_string()).collect::<Vec<String>>();

    let console_level = log_level[0].trim().to_uppercase().parse::<log::LevelFilter>().unwrap_or(log::LevelFilter::Warn);
    // let console_level = dev_or_prod!(log::LevelFilter::Debug, log::LevelFilter::Warn);

    let mut config = log4rs::Config::builder()
        .appender(logfile_get(log::LevelFilter::Debug, "debug"))
        .appender(logfile_get(log::LevelFilter::Info, "info"))
        .appender(logfile_get(log::LevelFilter::Warn, "warn"))
        .appender(logfile_get(log::LevelFilter::Error, "error"))
        .appender(Appender::builder().filter(Box::new(ThresholdFilter::new(console_level))).build(
            "console",
            Box::new(ConsoleAppender::builder().encoder(Box::new(PatternEncoder::new(parttern))).target(Target::Stdout).build()),
        ));

    // 考虑 RUST_LOG = "xxx=warn" 的情况
    if log_level.len() > 1 {
        for i in 1..log_level.len() {
            let (name, level) = log_level[i].split_two("=");
            let name = name.trim().to_string();
            if name.is_empty() || level.is_empty() {
                continue;
            }
            let level = level.trim().to_uppercase().parse::<log::LevelFilter>().unwrap_or(log::LevelFilter::Warn);

            // 添加日志配置
            config = config.logger(log4rs::config::Logger::builder().build(name, level));
        }
    }

    // 添加日志配置：这些模块不打印日志
    let offs = off_libs.split_arr(",");
    for off in offs {
        if off.trim().is_empty() {
            continue;
        }
        
        config = config.logger(log4rs::config::Logger::builder().build(off, LevelFilter::Off));
    }

    /* .logger(log4rs::config::Logger::builder().build("ureq", LevelFilter::Info))
    .logger(
        log4rs::config::Logger::builder()
            .build("rbatis", dev_or_prod!(LevelFilter::Info, LevelFilter::Warn)),
    )
    .logger(log4rs::config::Logger::builder().build("rustls", LevelFilter::Info))
    .logger(log4rs::config::Logger::builder().build("reqwest", LevelFilter::Info))
    .logger(log4rs::config::Logger::builder().build("hyper", LevelFilter::Info))
    .logger(log4rs::config::Logger::builder().build("sled", LevelFilter::Info))
    .logger(log4rs::config::Logger::builder().build("isahc", LevelFilter::Warn))
    .logger(log4rs::config::Logger::builder().build("mqtt_async_client", LevelFilter::Warn))
    .logger(log4rs::config::Logger::builder().build("teloxide", LevelFilter::Off))
    .logger(log4rs::config::Logger::builder().build("tao::platform_impl", LevelFilter::Error)) */

    let config = config.build(Root::builder().appenders(appenders).build(log::LevelFilter::Debug)).unwrap();

    log4rs::init_config(config)?;
    Ok(())
}

#[test]
fn test() {
    init().unwrap();
    for i in 0..100 {
        debug!("test debug log");
        info!("test info log");
        warn!("test warn log");
        error!("test error log");
        std::thread::sleep(std::time::Duration::from_millis(1000));
    }
}